package com.big_data_studio.service.impl.user;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.big_data_studio.exception.CustomException;
import com.big_data_studio.dto.RegisterParm;
import com.big_data_studio.dto.UserParm;
import com.big_data_studio.entity.Role;
import com.big_data_studio.entity.user.User;
import com.big_data_studio.entity.user.UserDetailsModel;
import com.big_data_studio.mapper.UserMapper;
import com.big_data_studio.service.IRoleService;
import com.big_data_studio.service.IUserRoleService;
import com.big_data_studio.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.big_data_studio.util.general.R;
import com.big_data_studio.util.general.RedisUtil;
import com.big_data_studio.util.general.TokenUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiao_jie
 * @since 2022-09-12
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    //获取认证结果
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserMapper userMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TokenUtil tokenUtil;

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private IRoleService roleService;

    @Resource
    private JavaMailSender javaMailSender;


    @Override
    public R userLogin(User user, HttpServletRequest request) {
        //初始化返回的信息
        Map<String, String> map = new HashMap<>();
        String uuid = null;
        //将用户名密码封装给认证对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getLoginName(), user.getPassword());
        //返回认证结果
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (Objects.isNull(authenticate)) {
            throw new CustomException(403, "认证失败");
        }
        //存储认证信息
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        //认证成功
        UserDetailsModel principal = (UserDetailsModel) authenticate.getPrincipal();
        //生成token
        uuid = UUID.randomUUID().toString();
        //保存到redis,过期时间为一天
        redisUtil.set(uuid, principal, 3600 * 12);
        //生成token返回到前端
        String jwt = tokenUtil.createJWT(principal.getUser().getId().toString(), uuid);
        // 存储token到集合中
        List<Integer> roles = roleService
                .listRolesByUserId(TokenUtil.getJwtUser().getId())
                .stream().map(Role::getId)
                .collect(Collectors.toList());
        String role = roles.toString();
        tokenUtil.putToken(uuid, jwt);
        map.put("token", jwt);
        map.put("roles", role);
        return R.ok(map, "登录成功！");
    }

    @Override
    public R userLogOut(String token) {
        Claims claims = tokenUtil.parseJWT(token);
        String uuid = claims.getSubject();
        tokenUtil.deleteToken(uuid);
        redisUtil.del(uuid);
        return R.ok("已经退出登录");
    }

    @Override
    public R getOne(Integer id) {
        User user = userMapper.selectById(id);
        return R.ok(user, "查询成功");
    }

    @Override
    public R list(UserParm userParm) {
        Page<User> page = userMapper.page(new Page<User>(userParm.getCurrent(), userParm.getSize()), userParm);
        return R.ok(page, "查询成功");
    }

    @Override
    // 事物回滚
    @Transactional
    public R add(User user) {
        try {
            // 密码加密
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String encode = bCryptPasswordEncoder.encode(user.getPassword());
            user.setPassword(encode);
            user.setCreateName(TokenUtil.getJwtUser().getUserName());
            userMapper.insert(user);
            userRoleService.registerUserRole(user.getId());
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return R.error("添加失败");
        }
        return R.ok("添加成功");
    }

    @Override
    // 事物回滚
    @Transactional
    public R update(User user) {
        try {
            User user1 = userMapper.selectById(user.getId());
            if (!Objects.equals(user1.getPassword(), user.getPassword())) {
                BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
                String encode = bCryptPasswordEncoder.encode(user.getPassword());
                user.setPassword(encode);
            }
            user.setUpdateName(TokenUtil.getJwtUser().getUpdateName());
            userMapper.updateById(user);
            userRoleService.saveRoleChanges(user.getId(), user.getRoles());
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return R.error("更新失败");
        }
        return R.ok("更新成功");
    }

    @Override
    public R del(Integer id) {
        try {
//            userMapper.deleteById(id);
            User user = userMapper.selectById(id);
            user.setUpdateName(TokenUtil.getJwtUser().getUpdateName());
            user.setIsDelete(true);
            userMapper.updateById(user);
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return R.error("删除成功");
        }
        return R.ok("删除成功");
    }

    @Override
    public R sendQQMailCode(String email) {
        String s = RandomUtil.randomNumbers(6);
        // 设置60秒后失效
        redisUtil.set(email, s, 60);
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom("1647231708@qq.com");
        simpleMailMessage.setTo(email);
        simpleMailMessage.setSubject("贵理工大数据工作室注册验证码");
        simpleMailMessage.setText(email + "用户你好,大数据工作室账号注册验证码:" + s);
        javaMailSender.send(simpleMailMessage);
        return R.ok("验证码发送成功，请前往QQ邮箱查看");
    }

    @Override
    @Transactional
    public R register(RegisterParm registerParm) {
        String code = (String) redisUtil.get(registerParm.getUser().getEmail());
        if (code == null) {
            return R.error("验证码过期，请重新获取！！");
        }
        if (!code.equals(registerParm.getAuthCode())) {
            return R.error("验证码不正确，请重新输入");
        }
        User user = null;
        try {
            user = registerParm.getUser();
            // 密码加密
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String encode = bCryptPasswordEncoder.encode(user.getPassword());
            user.setPassword(encode);
            userMapper.insert(user);
            userRoleService.registerUserRole(user.getId());
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return R.error("添加失败");
        }
        return R.ok("注册成功，请重新登录");
    }
}
